package com.imyuanma.qingyun.common.config.interceptor;

import com.imyuanma.qingyun.common.client.monitor.trace.TraceContext;
import com.imyuanma.qingyun.common.util.StringUtil;
import com.imyuanma.qingyun.common.util.UuidUtil;
import com.imyuanma.qingyun.common.util.constants.CommonConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 全链路追踪拦截器
 * @author imrookie
 * @date 2018/10/1
 */
@Component("traceInterceptor")
public class TraceInterceptor implements ICommonInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(TraceInterceptor.class);

    private static final String TRACE_SET = "TRACE_SET_TraceInterceptor";

    /**
     * 返回traceId
     * @return
     */
    public static String getTraceId(){
        return TraceContext.getTraceId();
    }

    /**
     * 设置traceId
     * @param traceId
     */
    public static void setTraceId(String traceId){
        TraceContext.traceId(traceId);
    }

    /**
     * 清除traceId
     */
    public static void removeTraceId(){
        TraceContext.clear();
    }

    //controller执行前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String traceId = getTraceId();
        if (StringUtil.isNotBlank(traceId)) {
            logger.debug("[TraceInterceptor] 当前请求已有traceId:{}", traceId);
            return true;
        }
        // 参数形式传入traceId
        traceId = request.getParameter(CommonConstants.TRACE_KEY);
        if (StringUtil.isBlank(traceId)) {
            // 请求头方式传入traceId
            traceId = request.getHeader(CommonConstants.TRACE_KEY);
        }
        if (StringUtil.isBlank(traceId)) {
            // 使用uuid作为traceId
            traceId = UuidUtil.getUUID();
        }
        request.setAttribute(TRACE_SET, Boolean.TRUE);
        // 设置MDC,日志打印时输出,方便跟踪请求
        setTraceId(traceId);
        // 写入响应头
        response.setHeader(CommonConstants.TRACE_KEY, traceId);
        return true;
    }

    //controller执行后,视图渲染前(发生异常不会走该方法)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    //做最后的处理,视图已经渲染完毕
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        if (Boolean.TRUE.equals(request.getAttribute(TRACE_SET))) {
            removeTraceId();
        }
    }

    /**
     * 注册拦截器
     * 接管WebMvcConfig中的addInterceptors
     *
     * @param registry
     */
    @Override
    public InterceptorRegistration addInterceptors(InterceptorRegistry registry) {
        //将自身注册到拦截器注册器中
        InterceptorRegistration interceptorRegistration = registry.addInterceptor(this).addPathPatterns("/**");//.excludePathPatterns("/static/**", "/page/**", "/favicon.ico");
        logger.info("[TraceInterceptor] 全链路跟踪拦截器注册完成.");
        return interceptorRegistration;
    }


}
